﻿using System;
using System.Collections.Generic;
using System.IO;
using CSScriptLibrary;

namespace Chimp.Core
{
    public class JointNode
    {
        public AsmHelper AH;
        public static void SetToList ( VarList vl )
        {
            foreach ( Var v in vl.Vars )
            {
                v.IsList = true;
            }
        }
        public void ParseVars ( Dictionary<string, Var> vars )
        {
            foreach ( string k in vars.Keys )
            {
                Var v = vars[ k ];
                string q = "";
                if ( v.IsStatic ) q = "static";
                if ( v.IsList )
                {
                    _cw.WriteLine ( "     public "+q+" List<" + TypeName ( v.CurType ) + "> " + v.Name + " = new List<" +
                                    TypeName ( v.CurType ) + ">();" );
                }
                else
                {
                    _cw.WriteLine ( "     public " +q+" "+ TypeName ( v.CurType ) + " " + v.Name + ";" );
                }
            }
        }

        public VarList GetVars ( )
        {
            VarList vl;
            vl = new VarList ( this );
            foreach ( Var v in vl.Vars )
            {
                if ( Vars.ContainsKey ( v.Name ) )
                {
                    Console.WriteLine ( "Var defined twice:" + v.Name );
                    continue;
                }

                Vars.Add ( v.Name, v );
            }
            return vl;
        }
        public void w(string s)
        {
            _cw.Write(s);

        }
        public virtual void Play(params object[] pars)
        {
            
         
        }

        public Dictionary<string, JointNode> Nodes = new Dictionary<string, JointNode>();
        public Dictionary<string, Var> Vars = new Dictionary<string, Var>();

        public string WhiteList =
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+= -][\"{}';:/?.>,<|\\";

        public FileStream _cf;
        public TextWriter _cw;
        public string _file = "";
        public FileStream _fs;
        public int _i;
        public TextReader _tr;

        public JointNode()
        {
            Parent = null;
        }

        public JointNode(string name, JointNode j)
        {
            Name = name;
            SetData(j);
        }

        public JointNode(JointNode j)
        {
            SetData(j);
        }

        public JointNode(string path)
        {
            _fs = new FileStream(path, FileMode.Open, FileAccess.Read);
            _tr = new StreamReader(_fs);
            _file = _tr.ReadToEnd();
            _i = 0;
            CreateOutput();
            ParseNode();

            _fs.Close();
            _fs = null;
            _tr = null;
            //CreateOutput();
        }

        public string Name { get; set; }
        public JointNode Parent { get; set; }

        public bool Eof
        {
            get { return _i >= _file.Length; }
        }

        public IFNode Root { get; set; }

        public string TypeName(string o)
        {
            switch (o)
            {
                case "Bool":
                    return "bool";
                case "Base":
                    return "ChimpBase";
                case "Sprite":
                    return "ChimpSprite";
                case "Image":
                    return "ActorImage";
                case "Text":
                    return "ActorText";
                case "Ship":
                    return "ActorShip";
                case "Scene":
                    return "ChimpScene";
                case "Int":
                case "Float":
                case "String":
                case "Char":
                case "Byte":
                case "Double":
                    return o.ToLower();
                case "ParticleEmitter":
                    return "ChimpParticleEmitter";
                case "Particle":
                    return "ChimpParticle";
                default:
                    return o;
            }
        }

        public virtual JointNode ParseExpr()
        {
          

            return new Expr(this);
        }

        public virtual JointNode ParseFunc()
        {
            string f = PeekTok();
            switch (f)
            {
                case "Create":

                    GetTok();
                    string n = GetTok();

                    var c = new Create(n, this);

                    return c;

                    break;
            }
            Console.WriteLine("Unknown Function:" + f);
         
            return null;

        }

        public void Produce()
        {
            WriteOutput();
            CloseOutput();
            Console.WriteLine("Output produced.");
        }

        public virtual void WriteNodes()
        {
            foreach (string k in Nodes.Keys)
            {
                JointNode n = Nodes[k];
                n._cw = _cw;
                if (_cw == null)
                {
                    Console.WriteLine("Bullshit!");
                    while (true)
                    {
                    }
                }
                n.Name = k;
                Console.WriteLine("Writing Output:" + k);
                n.WriteOutput();
            }
        }

        public virtual void CreateOutput()
        {
        }

        public virtual void CloseOutput()
        {
        }

        public virtual void WriteOutput()
        {
        }

        public JointNode SetNode(string id, JointNode n)
        {
            if (Nodes.ContainsKey(id))
            {
                Nodes.Remove(id);
            }
            Nodes.Add(id, n);
            return n;
        }

        public virtual void WriteNode()
        {
        }

        public JointNode GetNode(string id)
        {
            if (Nodes.ContainsKey(id))
            {
                return Nodes[id];
            }
            return null;
        }

        public void SetData(JointNode j)
        {
            _fs = j._fs;
            _tr = j._tr;
            _file = j._file;
            _i = j._i;
            _cf = j._cf;
            _cw = j._cw;
            Parent = j;
            Vars = j.Vars;
            ParseNode();
            Parent._i = _i;
        }

        public void l(string l)
        {
            _cw.WriteLine(l);
        }

        public virtual void WriteCSharpHeader()
        {
        }

        public virtual void WriteCSharpFooter()
        {
        }

        public virtual void ParseNode()
        {
        }
        public JointNode(string t1,string t2)
        {
            _file = t1;
            _i = 0;
            ParseNode ( );
        }
        public string PeekC()
        {
            if ( _i >= _file.Length ) return "";
            return _file.Substring(_i, 1);
        }

        public string GetC()
        {
            _i++;
            return _file.Substring(_i - 1, 1);
        }

        public string PeekTok()
        {
            int i = _i;
            string tok = GetTok();
            _i = i;
            return tok;
        }

        public string GetTok()
        {
            while (!Eof)
            {
                string t = GetTok2();
                if (t == "")
                {
                    if (_i < _file.Length)
                    {
                        continue;
                    }
                    return "";
                }
                if (t.Length > 0 && t != "\n" && t != "\0" && t != "\t" && t[0] != 0)
                {
                    if (t.Length == 1)
                    {
                        if (!WhiteList.Contains(t))
                        {
                            continue;
                        }
                    }
                    else
                    {
                        string nt = "";
                        for (int i = 0; i < t.Length; i++)
                        {
                            if (WhiteList.Contains(t[i].ToString()))
                            {
                                //t=t.Replace(t[i].ToString(), "");
                                nt += t[i].ToString();
                            }
                            //for (int w = 0; w < WhiteList.Length; w++)
                            // {
                        }
                        t = nt;
                    }
                    return t;
                }
            }
            return "";
        }

        public string GetTok2()
        {
            string tok = "";
            bool str = false;
            if (PeekC() == "\"")
            {
                str = true;
                _i++;
            }
            switch (PeekC())
            {
                case "[":
                case "]":
                case "=":
                case "\\":
                case "+":
                case "-":
                case ";":
                case "/":
                case "*":
                case ":":
                case "(":
                case ")":
                case "{":
                case "}":
                case ",":
                case "<":
                case ">":
                case ".":
                    return GetC();
                    break;
                case "\"":
                    str = true;
                    break;
            }

            while (!Eof)
            {
                string c = PeekC();
            
                if (c == " " || c == " " || c == "\t")
                {
                    if (tok.Length == 0)
                    {
                        _i++;
                        continue;
                    }
                }
                if (!WhiteList.Contains(c) || c == "")
                {
                    _i++;
                    return tok;
                }
                //    Console.WriteLine("C:" + c+"!");
                switch (c)
                {
                    case "[":
                    case "]":
                    case ".":
                    case ",":
                    case "<":
                    case ">":
                    case "|":
                    case "\\":
                    case ":":
                    case ";":
                    case "(":
                    case ")":
                    case "{":
                    case "}":
                    case "=":
                    case "+":
                    case "/":
                    case "*":
                    case "-":
                        if (!str)
                        {
                            return tok;
                        }
                        tok += GetC();
                        break;
                    case "\"":
                        if (str)
                        {

                            _i++;
                            return "\""+tok+"\"";
                        }
                        return tok;
                        break;
                    case " ":
                        if (!str)
                        {
                            _i++;
                            return tok;
                        }
                        tok += " ";
                        _i++;
                        break;
                    case "  ":
                    case "\t":
                        if (!str)
                        {
                            _i++;
                            return tok;
                        }
                        tok += "  ";
                        break;
                    default:
                        tok += GetC();
                        break;
                }
                if (c == "\n" || c == "\r" || c == "\0")
                {
                    _i++;
                    break;
                }
            }
            return tok;
        }

        private string UntilTok(string tok)
        {
            string r = "";
            while (true)
            {
                string c = PeekTok();
                if (c == tok)
                {
                    return r;
                }

                r += GetTok();
                if (_i == _file.Length)
                {
                    return r;
                }
            }
        }
    }
}